package com.bsfcs.rag.service;

import com.bsfcs.rag.entity.Contract;
import com.bsfcs.rag.entity.ContractLxPlan;
import com.bsfcs.rag.entity.ContractPaymoney;
import com.bsfcs.rag.entity.Contractjxfpdj;
import com.bsfcs.rag.entity.Invoice;
import com.bsfcs.rag.entity.Project;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import lombok.Getter;
import lombok.Setter;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Getter
@Setter
public class ContractProjectDataDTO {
    private String projectId;
    private Project project;
    private List<ContractDetail> contracts;
    
    // 用于JSON序列化时过滤字段
    @JsonIgnore
    private transient ContractDataQueryConfig contractDataQueryConfig;

    // 定义金额字段列表
    private static final Set<String> AMOUNT_FIELDS = Set.of(
        "contract_total_money",
        "yj_income",
        "yj_cost",
        "yj_ml",
        "yj_jl",
        "jhtje",
        "plan_perform_amount",
        "real_perform_amount",
        "node_amount",
        "amount_cashed",
        "deduction_amount",
        "all_money",
        "paid_money",
        "apply_money",
        "tax_amount",
        "invoice_amount",
        "tax_money",
        "not_tax_money",
        "total_invoice_amount",
        "remaining_invoice_amount",
        "total_tax_invoice_amount",
        "total_tax"
    );

    public ContractProjectDataDTO(String projectId, List<ContractDetail> contracts) {
        this.projectId = projectId;
        this.contracts = contracts;
    }
    
    public ContractProjectDataDTO(Project project, List<ContractDetail> contracts) {
        this.projectId = project.getId();
        this.project = project;
        this.contracts = contracts;
    }
    
    public ContractProjectDataDTO(String projectId, List<ContractDetail> contracts, ContractDataQueryConfig contractDataQueryConfig) {
        this.projectId = projectId;
        this.contractDataQueryConfig = contractDataQueryConfig;
        
        // 在构造时就进行字段过滤
        if (contracts != null && contractDataQueryConfig != null) {
            this.contracts = contracts.stream()
                .map(detail -> detail.filterFieldsForJson(contractDataQueryConfig))
                .collect(Collectors.toList());
        } else {
            this.contracts = contracts;
        }
    }
    
    public ContractProjectDataDTO(Project project, List<ContractDetail> contracts, ContractDataQueryConfig contractDataQueryConfig) {
        this.projectId = project.getId();
        this.project = project;
        this.contracts = contracts;
        this.contractDataQueryConfig = contractDataQueryConfig;
        
        // 在构造时就进行字段过滤
        if (contracts != null && contractDataQueryConfig != null) {
            // 过滤项目字段
            if (contractDataQueryConfig.hasProjectFields()) {
                this.project = filterProjectFields(project, contractDataQueryConfig.getProjectFields());
            }
            
            this.contracts = contracts.stream()
                .map(detail -> detail.filterFieldsForJson(contractDataQueryConfig))
                .collect(Collectors.toList());
        } else {
            this.contracts = contracts;
        }
    }
    
    /**
     * 过滤项目字段
     * @param project 项目对象
     * @param fields 要保留的字段
     * @return 过滤后的项目对象
     */
    private Project filterProjectFields(Project project, Set<String> fields) {
        if (project == null || fields == null || fields.isEmpty()) {
            return project;
        }
        
        Project filteredProject = new Project();
        Class<?> clazz = project.getClass();
        
        // 获取所有声明的字段（包括私有字段）
        Field[] allFields = clazz.getDeclaredFields();
        for (Field field : allFields) {
            try {
                if (fields.contains(field.getName())) {
                    field.setAccessible(true);
                    Field targetField = filteredProject.getClass().getDeclaredField(field.getName());
                    targetField.setAccessible(true);
                    Object value = field.get(project);
                    targetField.set(filteredProject, value);
                }
            } catch (Exception e) {
                // 忽略无法访问或设置的字段
            }
        }
        
        return filteredProject;
    }

    public String toModelString() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.writeValueAsString(this);
    }

    public String toChineseModelString() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonString = objectMapper.writeValueAsString(this);
        JsonNode jsonNode = objectMapper.readTree(jsonString);
        ObjectNode chineseNode = convertToChinese(jsonNode);
        return objectMapper.writeValueAsString(chineseNode);
    }

    private ObjectNode convertToChinese(JsonNode node) {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode chineseNode = mapper.createObjectNode();
        
        if (node.isObject()) {
            node.fields().forEachRemaining(entry -> {
                String key = entry.getKey();
                JsonNode value = entry.getValue();
                String chineseKey = getChineseFieldName(key);
                
                // 如果是金额字段且值不为null，则在值后添加"元"
                if (AMOUNT_FIELDS.contains(key) && value != null && !value.isNull()) {
                    if (value.isNumber()) {
                        chineseNode.put(chineseKey, value.asText() + "元");
                    } else if (value.isTextual()) {
                        try {
                            new BigDecimal(value.asText());
                            chineseNode.put(chineseKey, value.asText() + "元");
                        } catch (NumberFormatException e) {
                            chineseNode.set(chineseKey, value);
                        }
                    } else {
                        chineseNode.set(chineseKey, value);
                    }
                } else if (value.isObject()) {
                    chineseNode.set(chineseKey, convertToChinese(value));
                } else if (value.isArray()) {
                    ArrayNode arrayNode = mapper.createArrayNode();
                    value.forEach(item -> {
                        if (item.isObject()) {
                            arrayNode.add(convertToChinese(item));
                        } else {
                            arrayNode.add(item);
                        }
                    });
                    chineseNode.set(chineseKey, arrayNode);
                } else {
                    chineseNode.set(chineseKey, value);
                }
            });
        }
        
        return chineseNode;
    }

    private String getChineseFieldName(String fieldName) {
        switch (fieldName) {
            case "projectId": return "项目ID";
            case "project": return "项目";
            case "project_name": return "项目名称";
            case "project_code": return "项目编号";
            case "contracts": return "合同列表";
            case "contract": return "合同";
            case "contracting_party_orgname": return "签约主体";
            case "contractLxPlans": return "合同履行节点列表";
            case "contractPaymoneys": return "付款记录列表";
            case "invoices": return "开票记录列表";
            case "contractjxfpdjs": return "进项发票记录列表";
            case "id": return "ID";
            case "project_id_field": return "项目ID";
            case "szhy": return "行业";
            case "cbxm_code": return "储备项目编号";
            case "cbxm_name": return "储备项目名称";
            case "code": return "编号";
            case "name": return "名称";
            case "opposite_contract_code": return "相对方合同编号";
            case "contract_total_money": return "合同总金额";
            case "signing_time": return "合同签约时间";
            case "begintime": return "合同开始时间";
            case "endtime": return "合同结束时间";
            case "jsfsname": return "结算方式";
            case "kxytname": return "款项用途";
            case "contract_biz_status": return "合同类别";
            case "cgfs_type": return "采购方式";
            case "htzs": return "合同制式";
            case "purchase_enabled": return "招投标方式";
            case "yj_income": return "合同预计收入";
            case "yj_cost": return "合同预计成本";
            case "yj_ml": return "合同预计毛利";
            case "gross_margin": return "毛利率";
            case "net_profit_margin": return "净利率";
            case "yj_jl": return "合同预计净利";
            case "jhtje": return "净合同金额";
            case "client_name": return "相对方名称";
            case "khxz": return "相对方类型";
            case "szhy_szhy_hy_name": return "行业名称";
            case "scale": return "规模";
            case "sf": return "省份";
            case "city_proper": return "市区";
            case "district_level": return "区级";
            case "address": return "地址";
            case "contracting_party": return "签约主体";
            case "signatory_id": return "签约人";
            case "isauthorized": return "签署授权";
            case "consortium_type": return "联合体类型";
            case "consortium_name": return "联合体名称";
            case "legal_representative": return "法定代表人";
            case "isconsortium": return "是否联合体";
            case "parentID": return "上级对象主键";
            case "deadline": return "计划履行日期";
            case "created": return "创建信息";
            case "enabled": return "是否启用";
            case "plan_perform_amount": return "计划履行金额";
            case "real_perform_date": return "实际履行日期";
            case "real_perform_amount": return "实际履行金额";
            case "is_performed": return "是否已履行";
            case "is_co_party_b": return "是否合同乙方";
            case "perform_party": return "履行方";
            case "tax_point": return "税点";
            case "billcode": return "单据号";
            case "billname": return "单据名称";
            case "payment_name": return "款项名称";
            case "node_date": return "节点日期";
            case "node_amount": return "节点金额";
            case "contract_amount": return "占合同额比例";
            case "terms_conditions": return "条款说明";
            case "remarks": return "备注";
            case "performance_number": return "履约编号";
            case "performance_number_flow": return "履约编号流水";
            case "performance_status": return "履约状态";
            case "serial_number": return "序号";
            case "constantonehundred": return "常量一百";
            case "performance_stage": return "履约阶段";
            case "nodeamount_method": return "节点金额计算方式";
            case "payment_id": return "款项ID";
            case "payment_code": return "款项编码";
            case "status_enab": return "履行状态";
            case "amount_cashed": return "实际回款金额";
            case "deduction_amount": return "扣款金额";
            case "carry_id": return "合同履约节点ID";
            case "billStatus": return "状态";
            case "processInstance": return "流程实例";
            case "JXPFDJD": return "进项发票登记单编号";
            case "contr_name": return "合同名称";
            case "contr_code": return "合同编号";
            case "pay_time": return "付款时间";
            case "coll_unit": return "收款单位";
            case "bank": return "开户行";
            case "bank_accou": return "银行账号";
            case "all_money": return "合同总金额";
            case "paid_money": return "已付金额";
            case "apply_money": return "本次申请金额";
            case "pay_method": return "支付方式";
            case "pay_remark": return "付款说明";
            case "agent": return "经办人";
            case "dept": return "所在部门";
            case "company": return "所在公司";
            case "parent_id": return "父级ID";
            case "create_user_id": return "创建人";
            case "org": return "所属单位";
            case "department": return "所属部门";
            case "create_time": return "创建时间";
            case "projectcode": return "项目编号";
            case "projectname": return "项目名称";
            case "applicant_time": return "申请时间";
            case "deduction_reason": return "扣款原因";
            case "contract_id": return "合同ID";
            case "contr_id_new": return "合同ID新";
            case "coll_unit_id": return "收款单位ID";
            case "pay_org": return "付款单位";
            case "pay_accountid": return "付款账户ID";
            case "pay_account": return "付款账户";
            case "pay_user": return "付款经办人";
            case "pay_bank": return "付款账户所在银行";
            case "pay_bz": return "付款账户币种";
            case "pay_nature": return "付款性质";
            case "pay_rate": return "税率";
            case "mark": return "备注";
            case "notes": return "付款说明原因";
            case "agentcode": return "经办人编码";
            case "deptcode": return "所在部门编码";
            case "jxpdjid": return "进项票发票登记ID";
            case "pay_org_id": return "付款单位ID";
            case "temp_pay_org_id": return "签约主体主键";
            case "pay_bill_type": return "付款单据";
            case "pay_org_name": return "付款主体";
            case "s_mak": return "收款单位备注";
            case "coll_unit_name": return "收款单位名称";
            case "is_pay_ctrl": return "控制财务填写";
            case "version": return "版本";
            case "billstatus": return "状态";
            case "processinstance": return "流程实例";
            case "tin": return "纳税人识别号";
            case "addr": return "地址";
            case "phone": return "电话";
            case "bank_account": return "开户银行账号";
            case "tax_amount": return "含税金额";
            case "use_info": return "用途";
            case "carry_node": return "履约节点";
            case "apply_user": return "申请人员";
            case "applicationdate": return "申请时间";
            case "applicationreason": return "申请事由";
            case "invoice_name": return "名称";
            case "duty_paragraph": return "税号";
            case "unitaddress": return "单位地址";
            case "operator_org": return "所属单位";
            case "operator_department": return "所属部门";
            case "operator_user_id": return "经办人";
            case "invoice_amount": return "开票金额";
            case "expectedarrivaltime": return "预计到账时间";
            case "terms_and_conditions": return "条款说明";
            case "psid": return "评审ID";
            case "invoice_id": return "相对方ID";
            case "contr_id": return "合同ID";
            case "project_id": return "项目ID";
            case "project_type": return "项目类型";
            case "project_amount": return "项目金额";
            case "customer_name": return "项目客户名称";
            case "customer_id": return "项目客户ID";
            case "carry_node_id": return "履约节点ID";
            case "total_invoice_amount": return "已开具不含税总额";
            case "remaining_invoice_amount": return "未开具发票总额";
            case "total_tax_invoice_amount": return "已开具含税总额";
            case "total_tax": return "税额总额";
            case "jbr_org_code": return "经办单位编码";
            case "jbr_dept_code": return "经办部门编码";
            case "jbr_code": return "经办人编码";
            case "fplx": return "发票类型";
            case "contract_entity": return "签约主体";
            case "fp_bill_type": return "常用发票类型";
            case "fp_bill_name": return "发票抬头名称";
            case "fp_bill_mark": return "开票备注";
            case "is_contract_entity": return "控制签约主体";
            case "psdate": return "审批完成时间";
            case "bill_code": return "发票代码";
            case "bill_num": return "发票号码";
            case "bill_date": return "开票日期";
            case "TIN": return "纳税人识别号";
            case "tax_money": return "含税金额";
            case "not_tax_money": return "不含税金额";
            case "curry_id": return "合同评审履约节点";
            case "clientname": return "客户相对方名称";
            default: return fieldName;
        }
    }

    @Getter
    @Setter
    public static class ContractDetail {
        private Map<String, Object> contract;
        private List<Map<String, Object>> contractLxPlans;
        private List<Map<String, Object>> contractPaymoneys;
        private List<Map<String, Object>> invoices;
        private List<Map<String, Object>> contractjxfpdjs;

        public ContractDetail(Map<String, Object> contract,
                              List<Map<String, Object>> contractLxPlans,
                              List<Map<String, Object>> contractPaymoneys,
                              List<Map<String, Object>> invoices,
                              List<Map<String, Object>> contractjxfpdjs) {
            this.contract = contract;
            this.contractLxPlans = contractLxPlans;
            this.contractPaymoneys = contractPaymoneys;
            this.invoices = invoices;
            this.contractjxfpdjs = contractjxfpdjs;
        }
        
        /**
         * 从实体对象创建ContractDetail
         * @param contract 合同实体
         * @param contractLxPlans 合同履行节点列表
         * @param contractPaymoneys 付款记录列表
         * @param invoices 开票记录列表
         * @param contractjxfpdjs 进项发票记录列表
         */
        public ContractDetail(Contract contract,
                              List<ContractLxPlan> contractLxPlans,
                              List<ContractPaymoney> contractPaymoneys,
                              List<Invoice> invoices,
                              List<Contractjxfpdj> contractjxfpdjs) {
            // 这里只是存储原始数据，实际过滤在filterFieldsForJson中完成
            // 为简化代码，这里直接存储完整数据
            this.contract = convertToMap(contract);
            this.contractLxPlans = contractLxPlans.stream().map(this::convertToMap).collect(Collectors.toList());
            this.contractPaymoneys = contractPaymoneys.stream().map(this::convertToMap).collect(Collectors.toList());
            this.invoices = invoices.stream().map(this::convertToMap).collect(Collectors.toList());
            this.contractjxfpdjs = contractjxfpdjs.stream().map(this::convertToMap).collect(Collectors.toList());
        }
        
        /**
         * 在JSON序列化时过滤字段
         * @param contractDataQueryConfig 查询配置
         * @return 过滤后的ContractDetail对象
         */
        public ContractDetail filterFieldsForJson(ContractDataQueryConfig contractDataQueryConfig) {
            // 如果没有配置任何字段，则返回完整数据
            if (contractDataQueryConfig == null || !contractDataQueryConfig.hasAnyFieldsConfigured()) {
                return this;
            }
            
            Map<String, Object> filteredContract = filterMap(this.contract, contractDataQueryConfig.getContractFields());
            List<Map<String, Object>> filteredContractLxPlans = filterMapList(this.contractLxPlans, contractDataQueryConfig.getContractLxPlanFields());
            List<Map<String, Object>> filteredContractPaymoneys = filterMapList(this.contractPaymoneys, contractDataQueryConfig.getContractPaymoneyFields());
            List<Map<String, Object>> filteredInvoices = filterMapList(this.invoices, contractDataQueryConfig.getInvoiceFields());
            List<Map<String, Object>> filteredContractjxfpdjs = filterMapList(this.contractjxfpdjs, contractDataQueryConfig.getContractjxfpdjFields());
            
            return new ContractDetail(
                filteredContract,
                filteredContractLxPlans,
                filteredContractPaymoneys,
                filteredInvoices,
                filteredContractjxfpdjs
            );
        }
        
        /**
         * 过滤Map中的字段
         * @param source 原始Map
         * @param fields 要保留的字段
         * @return 过滤后的Map
         */
        private Map<String, Object> filterMap(Map<String, Object> source, Set<String> fields) {
            if (source == null || fields == null || fields.isEmpty()) {
                return source;
            }
            
            Map<String, Object> filtered = new HashMap<>();
            for (String field : fields) {
                if (source.containsKey(field)) {
                    filtered.put(field, source.get(field));
                }
            }
            return filtered;
        }
        
        /**
         * 过滤Map列表中的字段
         * @param sourceList 原始Map列表
         * @param fields 要保留的字段
         * @return 过滤后的Map列表
         */
        private List<Map<String, Object>> filterMapList(List<Map<String, Object>> sourceList, Set<String> fields) {
            if (sourceList == null || fields == null || fields.isEmpty()) {
                return sourceList;
            }
            
            return sourceList.stream()
                .map(map -> filterMap(map, fields))
                .collect(Collectors.toList());
        }
        
        /**
         * 将实体对象转换为Map
         * @param obj 实体对象
         * @return Map表示
         */
        private Map<String, Object> convertToMap(Object obj) {
            if (obj == null) {
                return null;
            }
            
            Map<String, Object> map = new HashMap<>();
            Class<?> clazz = obj.getClass();
            
            // 获取所有声明的字段（包括私有字段）
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                try {
                    field.setAccessible(true);
                    Object value = field.get(obj);
                    map.put(field.getName(), value);
                } catch (IllegalAccessException e) {
                    // 忽略无法访问的字段
                }
            }
            
            return map;
        }
    }
}